#include "stdafx.h"
#include "BehaviorAnalysis.h"
using namespace std;

BehaviorAnalysis::BehaviorAnalysis()
{
	this->bufferSize = 0;
	this->diffusionDistanceEnabled = false;
	this->fileheadEnabled = false;
	this->nStep = 0;
	this->orderParameterEnabled = 0;
	this->positionVelocityEnabled = 0;
}

BehaviorAnalysis::BehaviorAnalysis (Configuration& config)
{
	if ( config.configurationEnabled == false )
	{
		cout<<"BehaviorAnalysis: configuration not enabled."<<endl;
	}
	else
	{
		this->bufferSize = config.bufferSize;
		this->diffusionDistanceEnabled = config.diffusionDistanceEnabled;
		this->fileheadEnabled = config.fileheadEnabled;
		this->nStep = 0;
		this->orderParameterEnabled = config.orderParameterEnabled;
		this->positionVelocityEnabled = config.positionVelocityEnabled;
	}
}

BehaviorAnalysis::~BehaviorAnalysis()
{
	if ( this->diffusionDistanceEnabled == true )
	{
		delete [] diffusionDistance; 
		diffusionDistance = NULL;
	}
	if ( this->orderParameterEnabled == true )
	{
		delete [] orderParameter;
		orderParameter = NULL;
	}
}

void BehaviorAnalysis::analyze( const Flock* flock)
{
	if ( this->diffusionDistanceEnabled == true )
		recordDiffusionDistance( flock);
	if ( this->orderParameterEnabled == true )
		recordOrderParameter( flock );
	if ( this->positionVelocityEnabled == true )
		writeToFile_PositionVelocity( flock );
	nStep++;
}


double BehaviorAnalysis::getDiffusionDistance( const Flock* flock)
{
	double s = 0;
	double t = 0;
	Vector_3D v;
	Vector_3D avg;
	if ( flock->nBirds <= 0)
	{
		cout<<"getDiffusionSize: nbirds = 0."<<endl;
		return -1;
	}
	for (int i = 0; i < flock->nBirds; i++)
	{
		avg = avg + flock->bird[i].X;
	}
	avg = avg / flock->nBirds;
	for (int i = 0; i < flock->nBirds; i++)
	{
		v = flock->bird[i].X - avg;
		s += v.x*v.x + v.y*v.y + v.z*v.z;
	}
	return sqrt(s/flock->nBirds);
}


string BehaviorAnalysis::getFileName( string prefix)
{
	time_t t = time(0);
	char tmp[64];
	strftime( tmp, sizeof(tmp), "%Y_%m_%d_%X",localtime(&t) );
	string filename(tmp);
	filename = prefix + string("_") + filename;
	filename = filename + string(".txt");
	string route("../data/");
	filename = route + filename;
	int location = 0;
	while (1)
	{
		location = filename.find(":");
		if(location == -1 ) 
			break;
		else
			filename[location] = '_';
	}
	return filename;
}

double BehaviorAnalysis::getOrderParameter(  const Flock* flock )
{
	Vector_3D avg;
	for (int i = 0; i < flock->nBirds; i++ )
	{
		avg = avg + flock->bird[i].V;
	}
	return  avg.norm() / flock->nBirds;
}


bool BehaviorAnalysis::init( const Flock* flock)
{	
	if ( this->diffusionDistanceEnabled == true)
	{
		if ( !this->openDiffusionDistance( flock )) return false;
	}
	if ( this->orderParameterEnabled == true)
	{
		if ( !this->openOrderParameter( flock )) return false;
	}
	return true;
}


void BehaviorAnalysis::writeToFile_PositionVelocity( const Flock* flock)
{
	string filename = getFileName( "Position and Velocity");
	ofstream fout;
	fout.open(filename, ios::out);
	if ( !fout )
	{
		cout<<"Could not open file "<<filename<<endl;
	}
	Ball_3D* first= flock->bird;
	for (int i = 0; i < flock->nBirds; i++)
	{
		fout<<first[i].X.x<<" "<<first[i].X.y<<" "<<first[i].X.z<<" ";
		fout<<first[i].V.x<<" "<<first[i].V.y<<" "<<first[i].V.z<<endl;
	}
	fout.close();
	cout<<"File done : position and velocity."<<endl;
}


bool BehaviorAnalysis::writeToFile_OrderParameter()
{	
	string filename = getFileName( "orderParameter");
	ofstream fout;
	fout.open(filename, ios::out | ios::app);
	if ( !fout )
	{
		cout<<"Could not open file "<<filename<<endl;
		return false;
	}
	for ( int i = 0; i < this->bufferSize ; i++)
	{
		fout<<orderParameter[i]<<endl;
	}
	fout.close();
	cout<<"File done : order parameter."<<endl;
	return true;
}
void BehaviorAnalysis::setConfiguration(Configuration& config)
{
	if ( config.configurationEnabled == false )
	{
		cout<<"BehaviorAnalysis: configuration not enabled."<<endl;
	}
	else
	{
		this->bufferSize = config.bufferSize;
		this->diffusionDistanceEnabled = config.diffusionDistanceEnabled;
		this->fileheadEnabled = config.fileheadEnabled;
		this->nStep = 0;
		this->orderParameterEnabled = config.orderParameterEnabled;
		this->positionVelocityEnabled = config.positionVelocityEnabled;
	}
}

double BehaviorAnalysis::spinWaveApproximationQuality( const Flock* flock )
{
	Vector_3D avg(0,0,0);
	for ( int i = 0; i < flock->nBirds; i++)
	{
		avg = avg + flock->bird[i].V;
	}
	avg = avg / flock->nBirds;
	return avg.norm();
}

void BehaviorAnalysis::writeFileHead(Configuration& config)
{
	string filename = getFileName("Parameters");
	ofstream fout;
	fout.open(filename, ios::out);
	if ( !fout )
	{
		cout<<"Could not open file"<<filename<<endl;
		return ;
	}
	fout<<"maxSteps : "<<config.maxSteps<<endl;
	fout<<"renderingEnabled :" << config.renderingEnabled<<endl;
	fout<<"bufferSize :"<< config.bufferSize<<endl;
	fout<<"diffusionDistanceEnabled : "<<config.diffusionDistanceEnabled<<endl;
	fout<<"fileheadEnabled : "<< config.fileheadEnabled<<endl;
	fout<<"orderParameterEnabled : "<<config.orderParameterEnabled<<endl;
	fout<<"positionVelocityEnabled : "<<config.positionVelocityEnabled<<endl;

	fout<<"alignmentStrength : "<<config.alignmentStrength<<endl;
	fout<<"alignemtnType : " <<config.alignmentType<<endl;
	fout<<"ballRadius : "<<config.ballRadius<<endl;
	fout<<"boundaryType : "<<config.boundaryType<<endl;
	fout<<"clusteringEnabled : "<<config.clusteringEnabled<<endl;
	fout<<"clusterNum : "<<config.clusterNum<<endl;
	fout<<"cohesionStrength : "<<config.cohesionStrength<<endl;
	fout<<"cohesionType : "<<config.cohesionType<<endl;
	fout<<"flockSize : "<<config.flockSize<<endl;
	fout<<"gridEnabled : "<<config.gridEnabled<<endl;
	fout<<"initRange : "<<config.initRange<<endl;
	fout<<"neighborNum : "<<config.neighborNum<<endl;
	fout<<"neighborRange : "<<config.neighborRange<<endl;
	fout<<"noiseStrength : "<<config.noiseStrength<<endl;
	fout<<"noiseType : "<<config.noiseType<<endl;
	fout<<"systemSize : "<<config.systemSize<<endl;
	fout<<"timeStep : "<<config.timeStep<<endl;
	fout<<"weightVelocity : "<<config.weightVelocity<<endl;

	fout<<"c_aS : "<<config.c_aS<<endl;
	fout<<"c_ra : "<<config.c_ra<<endl;
	fout<<"c_rb : "<<config.c_rb<<endl;
	fout<<"c_re : "<<config.c_re<<endl;
	fout<<"c_rS : "<<config.c_rS<<endl;
	fout.close();
}
bool BehaviorAnalysis::writeToFile_DiffusionDistance()
{	
	string filename = getFileName( "DiffusionDistance");
	ofstream fout;
	fout.open(filename, ios::out | ios::app);
	if ( !fout )
	{
		cout<<"Could not open file "<<filename<<endl;
		return false;
	}
	for ( int i = 0; i < this->bufferSize ; i++)
	{
		fout<<diffusionDistance[i]<<endl;
	}
	fout.close();
	cout<<"File done : diffusion distance."<<endl;
	return true;
}
void BehaviorAnalysis::writeToFile( const Flock* flock, string prefix)
{
;
}

bool BehaviorAnalysis::openDiffusionDistance( const Flock* flock)
{
	if ( (diffusionDistance = new double [this->bufferSize]) == NULL )
		return false;
	memset( diffusionDistance, 0, sizeof(double)*this->bufferSize);
	return true;
}

bool BehaviorAnalysis::openOrderParameter( const Flock*  flock)
{
	if ( (orderParameter = new double [this->bufferSize]) == NULL)
		return false;
	memset( orderParameter, 0, sizeof(double)*this->bufferSize);
	return true;
}

void BehaviorAnalysis::reallocateSpace(int flag)
{
	if (flag == SAME)
	{
		nStep = 0;
	}
}


void BehaviorAnalysis::recordDiffusionDistance(const Flock* flock)
{
	if ( nStep < bufferSize )
	{
		orderParameter[nStep] = getDiffusionDistance( flock );
	}
	else 
	{
		writeToFile_DiffusionDistance( );
		reallocateSpace( SAME );
	}
}

void BehaviorAnalysis::recordOrderParameter(const Flock* flock)
{
	if ( nStep < bufferSize )
	{
		orderParameter[nStep] = getOrderParameter( flock );
	}
	else 
	{
		writeToFile_OrderParameter();
		reallocateSpace( SAME );
	}
}


